package com.ticket.sass.ticketserver.handler

import com.ticket.sass.ticketserver.dto.output.ResultWrapOutput
import com.ticket.sass.ticketserver.exception.*
import com.ticket.sass.common.ticketserver.exceptions.BaseException as CommonTicketServerBaseException
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver
import org.springframework.boot.web.error.ErrorAttributeOptions
import org.springframework.boot.web.servlet.error.ErrorAttributes
import org.springframework.http.converter.HttpMessageNotReadableException
import org.springframework.validation.BindException
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.ResponseBody
import javax.servlet.http.HttpServletRequest

@ControllerAdvice
@RequestMapping("/error")
class ExceptionHandler(val errorAttributes: ErrorAttributes?, errorViewResolvers: MutableList<ErrorViewResolver>?) : AbstractErrorController(errorAttributes, errorViewResolvers) {
   private val logger: Logger = LoggerFactory.getLogger(ExceptionHandler::class.java)

    private val errorAttributeOptions = ErrorAttributeOptions.of(
        ErrorAttributeOptions.Include.MESSAGE,
        ErrorAttributeOptions.Include.STACK_TRACE,
        ErrorAttributeOptions.Include.EXCEPTION
    )

    @ExceptionHandler(
        InternalException::class,
        BadRequestException::class,
        ConfigException::class,
        UnauthorizedException::class,
    )
    @ResponseBody
    fun internalException(request: HttpServletRequest?, exception: BaseException): ResultWrapOutput<Any?> {
        val body: Map<String, Any> = getErrorAttributes(request, errorAttributeOptions)

        logger.error(body["trace"].toString())

        return ResultWrapOutput(
            ResultWrapOutput.Code.ERROR.value,
            exception.errorMessage ?: exception.errorCode.reasonPhrase,
            exception.errorCode.value,
            exception.errorMessage ?: exception.errorCode.reasonPhrase
        )
    }

    @ResponseBody
    @ExceptionHandler(CommonTicketServerBaseException::class)
    fun internalException(request: HttpServletRequest?, exception: CommonTicketServerBaseException): ResultWrapOutput<Any?> {
        val body: Map<String, Any> = getErrorAttributes(request, errorAttributeOptions)

        logger.error(body["trace"].toString())

        return ResultWrapOutput(
            ResultWrapOutput.Code.ERROR.value,
            exception.errorMessage ?: ResultWrapOutput.ErrorCode.PLATFORM_ERROR.reasonPhrase,
            ResultWrapOutput.ErrorCode.PLATFORM_ERROR.value,
            exception.errorMessage ?: ResultWrapOutput.ErrorCode.PLATFORM_ERROR.reasonPhrase,
        )
    }

    @RequestMapping
    @ResponseBody
    @ExceptionHandler(HttpMessageNotReadableException::class)
    fun error(request: HttpServletRequest?): ResultWrapOutput<Any?> {
        val body: Map<String, Any> = getErrorAttributes(request, errorAttributeOptions)

        logger.error("HttpMessageNotReadableException $body")

        val message = body["error"] as? String

        return ResultWrapOutput(
            ResultWrapOutput.Code.ERROR.value,
            message ?: ResultWrapOutput.ErrorCode.CLIENT_ERROR.reasonPhrase,
            ResultWrapOutput.ErrorCode.CLIENT_ERROR.value,
            message ?: ResultWrapOutput.ErrorCode.CLIENT_ERROR.reasonPhrase,
        )
    }

    @ExceptionHandler(BindException::class)
    @ResponseBody
    fun validError(exception: BindException): ResultWrapOutput<Any?> {
        val message = exception.fieldError?.defaultMessage ?: "参数校验有误"

        return ResultWrapOutput(
            ResultWrapOutput.Code.ERROR.value,
            message,
            ResultWrapOutput.ErrorCode.BAD_REQUEST.value,
            message,
        )
    }

    @ExceptionHandler(MethodArgumentNotValidException::class)
    @ResponseBody
    fun validError(exception: MethodArgumentNotValidException): ResultWrapOutput<Any?> {
        val message = exception.bindingResult.fieldError?.defaultMessage ?: "参数校验有误"

        return ResultWrapOutput(
            ResultWrapOutput.Code.ERROR.value,
            message,
            ResultWrapOutput.ErrorCode.BAD_REQUEST.value,
            message,
        )
    }
}